#!/usr/bin/lua

local cjson = require("cjson")
local uci = require "uci"

local list = {
	status = {}
}

local function status()
    local c = uci.cursor()
    local fwd = { }

    local ipt = io.popen("iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null")
    if ipt then
        local lease_file = c:get("upnpd", "config", "upnp_lease_file")
        local upnpf = lease_file and io.open(lease_file, "r")

        while true do
            local ln = ipt:read("*l")
            if not ln then
                break
            elseif ln:match("^%d+") then
                local num, proto, extport, intaddr, intport = ln:match("^(%d+).-([a-z]+).-dpt:(%d+) to:(%S-):(%d+)")
                local descr = ""

                if num and proto and extport and intaddr and intport then
                    num     = tonumber(num)
                    extport = tonumber(extport)
                    intport = tonumber(intport)

                    if upnpf then
                        local uln = upnpf:read("*l")
                        if uln then descr = uln:match(string.format("^%s:%d:%s:%d:%%d*:(.*)$", proto:upper(), extport, intaddr, intport)) end
                        if not descr then descr = "" end
                    end

                    local host_hint = intaddr

                    fwd[#fwd + 1] = {
                        num     = num,
                        proto   = proto:upper(),
                        extport = extport,
                        intaddr = intaddr,
                        host_hint = host_hint,
                        intport = intport,
                        descr = descr
                    }
                end
            end
        end

        if upnpf then upnpf:close() end
        ipt:close()
    end

    return fwd
end

if arg[1] == "list" then
	print(cjson.encode(list))
elseif arg[1] == "call" then
    if arg[2] == "status" then
        local entries = status()

        if #entries == 0 then
            print('{"entries": []}')
        else
            print(cjson.encode({entries = entries}))
        end
	end
end